package cn.micro.system.manage.service.impl.oss;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.micro.system.manage.common.enums.FileStoreTypeEnum;
import cn.micro.system.manage.common.exception.SystemException;
import cn.micro.system.manage.entity.AssetOdsFileRecordInfo;
import cn.micro.system.manage.service.AssetOdsFileRecordInfoService;
import cn.micro.system.manage.service.OssService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Component
@ConditionalOnProperty(value = "oss.type", havingValue = "local")
@ConfigurationProperties(prefix = "oss.local")
@RequiredArgsConstructor
@Data
@Slf4j
public class LocalOssServiceImpl implements OssService {


    private String basePath;

    private final AssetOdsFileRecordInfoService assetOdsFileRecordInfoService;

    @Override
    public List<String> upload(MultipartFile[] files, String path) {
        List<String> fileIds = new ArrayList<>();
        for (MultipartFile file : files){
            String originalName = file.getOriginalFilename();
            // 生成文件名(日期文件夹)
            String suffix = FileUtil.getSuffix(file.getOriginalFilename());
            String uuid = IdUtil.simpleUUID();
            String fileName = DateUtil.format(LocalDateTime.now(), "yyyyMMdd") + "/" + uuid + "." + suffix;
            Path savePath = Paths.get(basePath,path,fileName);
            File newFile = savePath.toFile();
            if (!newFile.getParentFile().exists()){
                newFile.getParentFile().mkdirs();
            }
            try {
                file.transferTo(newFile);
            } catch (Exception e) {
                e.printStackTrace();
            }
            AssetOdsFileRecordInfo recordInfo = new AssetOdsFileRecordInfo();
            recordInfo.setUrl(savePath.toString().substring(basePath.length()));
            recordInfo.setOriginalName(originalName);
            recordInfo.setStoreName(newFile.getName());
            recordInfo.setStoreType(FileStoreTypeEnum.LOCAL_TYPE.getValue());
            assetOdsFileRecordInfoService.save(recordInfo);
            fileIds.add(recordInfo.getId().toString());
        }
        return fileIds;
    }

    @Override
    public boolean delete(Long id) {
        AssetOdsFileRecordInfo recordInfo = assetOdsFileRecordInfoService.getById(id);
        if (recordInfo == null || recordInfo.getUrl() == null){
            throw new RuntimeException("文件不存在");
        }
        Path path = Paths.get(basePath, recordInfo.getUrl());
        File file = path.toFile();
        if (file.exists()){
            return file.delete();
        }
        return false;
    }

    @Override
    public void download(Long id, String rename, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        AssetOdsFileRecordInfo recordInfo = assetOdsFileRecordInfoService.getById(id);
        if (recordInfo == null || recordInfo.getUrl() == null){
            throw new SystemException("文件不存在");
        }
        Path path= Paths.get(basePath, recordInfo.getUrl());
        if (!Files.exists(path)){
            throw new SystemException("文件不存在");
        }
        File file = path.toFile();
        response.reset();
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setContentLength((int) path.toFile().length());
        response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(file.getName(), "UTF-8"));

        /*
         * 跨域配置
         * */
        response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {
            byte[] buffer = new byte[1024];
            ServletOutputStream outputStream = response.getOutputStream();
            int i;
            while ((i = bis.read(buffer)) != -1) {
                outputStream.write(buffer, 0, i);
                outputStream.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SystemException("文件下载失败");
        }
    }

    @Override
    public void findView(Long id, HttpServletResponse response) {
        AssetOdsFileRecordInfo recordInfo = assetOdsFileRecordInfoService.getById(id);
        if (recordInfo == null || recordInfo.getUrl() == null){
            throw new SystemException("文件不存在");
        }
        Path path= Paths.get(basePath, recordInfo.getUrl());
        if (!Files.exists(path)){
            throw new SystemException("文件不存在");
        }
        File file = path.toFile();
        if (file.exists()) {
            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
